Skip to contentMethod: findMostSpecificWrapper(List, Class[], boolean, String)
1: /*
2: * Copyright (c) 1997, 2021 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: * Copyright 2004 The Apache Software Foundation
5: *
6: * Licensed under the Apache License, Version 2.0 (the "License");
7: * you may not use this file except in compliance with the License.
8: * You may obtain a copy of the License at
9: *
10: * http://www.apache.org/licenses/LICENSE-2.0
11: *
12: * Unless required by applicable law or agreed to in writing, software
13: * distributed under the License is distributed on an "AS IS" BASIS,
14: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15: * See the License for the specific language governing permissions and
16: * limitations under the License.
17: */
18:
19: package jakarta.el;
20:
21: import java.lang.reflect.Array;
22: import java.lang.reflect.Constructor;
23: import java.lang.reflect.InvocationTargetException;
24: import java.lang.reflect.Method;
25: import java.lang.reflect.Modifier;
26: import java.text.MessageFormat;
27: import java.util.ArrayList;
28: import java.util.HashMap;
29: import java.util.Iterator;
30: import java.util.List;
31: import java.util.Locale;
32: import java.util.Map;
33: import java.util.MissingResourceException;
34: import java.util.ResourceBundle;
35:
36: /**
37: * Utility methods for this portion of the Jakarta Expression Language implementation
38: *
39: * <p>
40: * Methods on this class use a Map instance stored in ThreadLocal storage to minimize the performance impact on
41: * operations that take place multiple times on a single Thread. The keys and values of the Map are implementation
42: * private.
43: *
44: * @author edburns
45: * @author Kin-man Chung
46: * @author Dongbin Nie
47: */
48: class ELUtil {
49:
50: /**
51: * This class may not be constructed.
52: */
53: private ELUtil() {
54: }
55:
56: /*
57: * For testing Backward Compatibility option static java.util.Properties properties = new java.util.Properties(); static
58: * { properties.setProperty("jakarta.el.bc2.2", "true"); }
59: */
60: public static ExpressionFactory exprFactory = ExpressionFactory.newInstance(/* properties */);
61:
62: /**
63: * <p>
64: * The <code>ThreadLocal</code> variable used to record the <code>jakarta.faces.context.FacesContext</code> instance for
65: * each processing thread.
66: * </p>
67: */
68: private static ThreadLocal<Map<String, ResourceBundle>> instance = new ThreadLocal<>() {
69: @Override
70: protected Map<String, ResourceBundle> initialValue() {
71: return (null);
72: }
73: };
74:
75: /**
76: * @return a Map stored in ThreadLocal storage. This may be used by methods of this class to minimize the performance
77: * impact for operations that may take place multiple times on a given Thread instance.
78: */
79: private static Map<String, ResourceBundle> getCurrentInstance() {
80: Map<String, ResourceBundle> result = instance.get();
81: if (result == null) {
82: result = new HashMap<>();
83: setCurrentInstance(result);
84: }
85:
86: return result;
87:
88: }
89:
90: /**
91: * Replace the Map with the argument context.
92: *
93: * @param context the Map to be stored in ThreadLocal storage.
94: */
95: private static void setCurrentInstance(Map<String, ResourceBundle> context) {
96: instance.set(context);
97: }
98:
99: /**
100: * Convenience method, calls through to getExceptionMessageString(ELContext,java.lang.String,Object []).
101: *
102: * @param context the ELContext from which the Locale for this message is extracted.
103: * @param messageId the messageId String in the ResourceBundle
104: *
105: * @return a localized String for the argument messageId
106: */
107: public static String getExceptionMessageString(ELContext context, String messageId) {
108: return getExceptionMessageString(context, messageId, null);
109: }
110:
111: /*
112: * <p>Return a Localized message String suitable for use as an Exception message. Examine the argument
113: * <code>context</code> for a <code>Locale</code>. If not present, use <code>Locale.getDefault()</code>. Load the
114: * <code>ResourceBundle</code> "jakarta.el.Messages" using that locale. Get the message string for argument
115: * <code>messageId</code>. If not found return "Missing Resource in Jakarta Expression Language implementation ??? messageId ???" with messageId
116: * substituted with the runtime value of argument <code>messageId</code>. If found, and argument <code>params</code> is
117: * non-null, format the message using the params. If formatting fails, return a sensible message including the
118: * <code>messageId</code>. If argument <code>params</code> is <code>null</code>, skip formatting and return the message
119: * directly, otherwise return the formatted message.</p>
120: *
121: * @param context the ELContext from which the Locale for this message is extracted.
122: *
123: * @param messageId the messageId String in the ResourceBundle
124: *
125: * @param params parameters to the message
126: *
127: * @return a localized String for the argument messageId
128: */
129: public static String getExceptionMessageString(ELContext context, String messageId, Object[] params) {
130: String result = "";
131: Locale locale = null;
132:
133: if (null == context || null == messageId) {
134: return result;
135: }
136:
137: if (null == (locale = context.getLocale())) {
138: locale = Locale.getDefault();
139: }
140:
141: if (locale != null) {
142: Map<String, ResourceBundle> threadMap = getCurrentInstance();
143: ResourceBundle resourceBundle = null;
144: if (null == (resourceBundle = threadMap.get(locale.toString()))) {
145: resourceBundle = ResourceBundle.getBundle("jakarta.el.PrivateMessages", locale);
146: threadMap.put(locale.toString(), resourceBundle);
147: }
148:
149: if (null != resourceBundle) {
150: try {
151: result = resourceBundle.getString(messageId);
152: if (null != params) {
153: result = MessageFormat.format(result, params);
154: }
155: } catch (IllegalArgumentException iae) {
156: result = "Can't get localized message: parameters to message appear to be incorrect. Message to format: " + messageId;
157: } catch (MissingResourceException mre) {
158: result = "Missing Resource in Jakarta Expression Language implementation: ???" + messageId + "???";
159: } catch (Exception e) {
160: result = "Exception resolving message in Jakarta Expression Language implementation: ???" + messageId + "???";
161: }
162: }
163: }
164:
165: return result;
166: }
167:
168: static ExpressionFactory getExpressionFactory() {
169: return exprFactory;
170: }
171:
172: static Constructor<?> findConstructor(Class<?> klass, Class<?>[] paramTypes, Object[] params) {
173: String methodName = "<init>";
174:
175: if (klass == null) {
176: throw new MethodNotFoundException("Method not found: " + klass + "." + methodName + "(" + paramString(paramTypes) + ")");
177: }
178:
179: if (paramTypes == null) {
180: paramTypes = getTypesFromValues(params);
181: }
182:
183: Constructor<?>[] constructors = klass.getConstructors();
184:
185: List<Wrapper> wrappers = Wrapper.wrap(constructors);
186:
187: Wrapper result = findWrapper(klass, wrappers, methodName, paramTypes, params);
188:
189: if (result == null) {
190: return null;
191: }
192:
193: return getConstructor(klass, (Constructor<?>) result.unWrap());
194: }
195:
196: static Object invokeConstructor(ELContext context, Constructor<?> constructor, Object[] params) {
197: Object[] parameters = buildParameters(context, constructor.getParameterTypes(), constructor.isVarArgs(), params);
198: try {
199: return constructor.newInstance(parameters);
200: } catch (IllegalAccessException iae) {
201: throw new ELException(iae);
202: } catch (IllegalArgumentException iae) {
203: throw new ELException(iae);
204: } catch (InvocationTargetException ite) {
205: throw new ELException(ite.getCause());
206: } catch (InstantiationException ie) {
207: throw new ELException(ie.getCause());
208: }
209: }
210:
211: static Method findMethod(Class<?> klass, String methodName, Class<?>[] paramTypes, Object[] params, boolean staticOnly) {
212: Method method = findMethod(klass, methodName, paramTypes, params);
213: if (staticOnly && !Modifier.isStatic(method.getModifiers())) {
214: throw new MethodNotFoundException("Method " + methodName + "for class " + klass + " not found or accessible");
215: }
216:
217: return method;
218: }
219:
220: /*
221: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
222: */
223: static Object invokeMethod(ELContext context, Method method, Object base, Object[] params) {
224:
225: Object[] parameters = buildParameters(context, method.getParameterTypes(), method.isVarArgs(), params);
226: try {
227: return method.invoke(base, parameters);
228: } catch (IllegalAccessException iae) {
229: throw new ELException(iae);
230: } catch (IllegalArgumentException iae) {
231: throw new ELException(iae);
232: } catch (InvocationTargetException ite) {
233: throw new ELException(ite.getCause());
234: }
235: }
236:
237: /*
238: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
239: */
240: static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes, Object[] paramValues) {
241: if (clazz == null || methodName == null) {
242: throw new MethodNotFoundException("Method not found: " + clazz + "." + methodName + "(" + paramString(paramTypes) + ")");
243: }
244:
245: if (paramTypes == null) {
246: paramTypes = getTypesFromValues(paramValues);
247: }
248:
249: Method[] methods = clazz.getMethods();
250:
251: List<Wrapper> wrappers = Wrapper.wrap(methods, methodName);
252:
253: Wrapper result = findWrapper(clazz, wrappers, methodName, paramTypes, paramValues);
254:
255: if (result == null) {
256: return null;
257: }
258:
259: return getMethod(clazz, (Method) result.unWrap());
260: }
261:
262: /*
263: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
264: */
265: @SuppressWarnings("null")
266: private static Wrapper findWrapper(Class<?> clazz, List<Wrapper> wrappers, String name, Class<?>[] paramTypes, Object[] paramValues) {
267: List<Wrapper> assignableCandidates = new ArrayList<>();
268: List<Wrapper> coercibleCandidates = new ArrayList<>();
269: List<Wrapper> varArgsCandidates = new ArrayList<>();
270:
271: int paramCount;
272: if (paramTypes == null) {
273: paramCount = 0;
274: } else {
275: paramCount = paramTypes.length;
276: }
277:
278: for (Wrapper w : wrappers) {
279: Class<?>[] mParamTypes = w.getParameterTypes();
280: int mParamCount;
281: if (mParamTypes == null) {
282: mParamCount = 0;
283: } else {
284: mParamCount = mParamTypes.length;
285: }
286:
287: // Check the number of parameters
288: if (!(paramCount == mParamCount || (w.isVarArgs() && paramCount >= mParamCount - 1))) {
289: // Method has wrong number of parameters
290: continue;
291: }
292:
293: // Check the parameters match
294: boolean assignable = false;
295: boolean coercible = false;
296: boolean varArgs = false;
297: boolean noMatch = false;
298: for (int i = 0; i < mParamCount; i++) {
299: if (i == (mParamCount - 1) && w.isVarArgs()) {
300: varArgs = true;
301: // exact var array type match
302: if (mParamCount == paramCount) {
303: if (mParamTypes[i] == paramTypes[i]) {
304: continue;
305: }
306: }
307:
308: // unwrap the array's component type
309: Class<?> varType = mParamTypes[i].getComponentType();
310: for (int j = i; j < paramCount; j++) {
311: if (!isAssignableFrom(paramTypes[j], varType)
312: && !(paramValues != null && j < paramValues.length && isCoercibleFrom(paramValues[j], varType))) {
313: noMatch = true;
314: break;
315: }
316: }
317: } else if (mParamTypes[i].equals(paramTypes[i])) {
318: } else if (isAssignableFrom(paramTypes[i], mParamTypes[i])) {
319: assignable = true;
320: } else {
321: if (paramValues == null || i >= paramValues.length) {
322: noMatch = true;
323: break;
324: } else {
325: if (isCoercibleFrom(paramValues[i], mParamTypes[i])) {
326: coercible = true;
327: } else {
328: noMatch = true;
329: break;
330: }
331: }
332: }
333: }
334: if (noMatch) {
335: continue;
336: }
337:
338: if (varArgs) {
339: varArgsCandidates.add(w);
340: } else if (coercible) {
341: coercibleCandidates.add(w);
342: } else if (assignable) {
343: assignableCandidates.add(w);
344: } else {
345: // If a method is found where every parameter matches exactly,
346: // return it
347: return w;
348: }
349:
350: }
351:
352: String errorMsg = "Unable to find unambiguous method: " + clazz + "." + name + "(" + paramString(paramTypes) + ")";
353: if (!assignableCandidates.isEmpty()) {
354: return findMostSpecificWrapper(assignableCandidates, paramTypes, false, errorMsg);
355: } else if (!coercibleCandidates.isEmpty()) {
356: return findMostSpecificWrapper(coercibleCandidates, paramTypes, true, errorMsg);
357: } else if (!varArgsCandidates.isEmpty()) {
358: return findMostSpecificWrapper(varArgsCandidates, paramTypes, true, errorMsg);
359: } else {
360: throw new MethodNotFoundException("Method not found: " + clazz + "." + name + "(" + paramString(paramTypes) + ")");
361: }
362:
363: }
364:
365: /*
366: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
367: */
368: private static Wrapper findMostSpecificWrapper(List<Wrapper> candidates, Class<?>[] matchingTypes, boolean elSpecific, String errorMsg) {
369: List<Wrapper> ambiguouses = new ArrayList<>();
370:• for (Wrapper candidate : candidates) {
371: boolean lessSpecific = false;
372:
373: Iterator<Wrapper> it = ambiguouses.iterator();
374:• while (it.hasNext()) {
375: int result = isMoreSpecific(candidate, it.next(), matchingTypes, elSpecific);
376:• if (result == 1) {
377: it.remove();
378:• } else if (result == -1) {
379: lessSpecific = true;
380: }
381: }
382:
383:• if (!lessSpecific) {
384: ambiguouses.add(candidate);
385: }
386: }
387:
388:• if (ambiguouses.size() > 1) {
389: throw new MethodNotFoundException(errorMsg);
390: }
391:
392: return ambiguouses.get(0);
393: }
394:
395: /*
396: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
397: */
398: private static int isMoreSpecific(Wrapper wrapper1, Wrapper wrapper2, Class<?>[] matchingTypes, boolean elSpecific) {
399: Class<?>[] paramTypes1 = wrapper1.getParameterTypes();
400: Class<?>[] paramTypes2 = wrapper2.getParameterTypes();
401:
402: if (wrapper1.isVarArgs()) {
403: // JLS8 15.12.2.5 Choosing the Most Specific Method
404: int length = Math.max(Math.max(paramTypes1.length, paramTypes2.length), matchingTypes.length);
405: paramTypes1 = getComparingParamTypesForVarArgsMethod(paramTypes1, length);
406: paramTypes2 = getComparingParamTypesForVarArgsMethod(paramTypes2, length);
407:
408: if (length > matchingTypes.length) {
409: Class<?>[] matchingTypes2 = new Class<?>[length];
410: System.arraycopy(matchingTypes, 0, matchingTypes2, 0, matchingTypes.length);
411: matchingTypes = matchingTypes2;
412: }
413: }
414:
415: int result = 0;
416: for (int i = 0; i < paramTypes1.length; i++) {
417: if (paramTypes1[i] != paramTypes2[i]) {
418: int r2 = isMoreSpecific(paramTypes1[i], paramTypes2[i], matchingTypes[i], elSpecific);
419: if (r2 == 1) {
420: if (result == -1) {
421: return 0;
422: }
423: result = 1;
424: } else if (r2 == -1) {
425: if (result == 1) {
426: return 0;
427: }
428: result = -1;
429: } else {
430: return 0;
431: }
432: }
433: }
434:
435: if (result == 0) {
436: // The nature of bridge methods is such that it actually
437: // doesn't matter which one we pick as long as we pick
438: // one. That said, pick the 'right' one (the non-bridge
439: // one) anyway.
440: result = Boolean.compare(wrapper1.isBridge(), wrapper2.isBridge());
441: }
442:
443: return result;
444: }
445:
446: /*
447: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
448: */
449: private static int isMoreSpecific(Class<?> type1, Class<?> type2, Class<?> matchingType, boolean elSpecific) {
450: type1 = getBoxingTypeIfPrimitive(type1);
451: type2 = getBoxingTypeIfPrimitive(type2);
452: if (type2.isAssignableFrom(type1)) {
453: return 1;
454: } else if (type1.isAssignableFrom(type2)) {
455: return -1;
456: } else {
457: if (elSpecific) {
458: /*
459: * Number will be treated as more specific
460: *
461: * ASTInteger only return Long or BigInteger, no Byte / Short / Integer. ASTFloatingPoint also.
462: *
463: */
464: if (matchingType != null && Number.class.isAssignableFrom(matchingType)) {
465: boolean b1 = Number.class.isAssignableFrom(type1) || type1.isPrimitive();
466: boolean b2 = Number.class.isAssignableFrom(type2) || type2.isPrimitive();
467: if (b1 && !b2) {
468: return 1;
469: } else if (b2 && !b1) {
470: return -1;
471: } else {
472: return 0;
473: }
474: }
475:
476: return 0;
477: } else {
478: return 0;
479: }
480: }
481: }
482:
483: /*
484: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
485: */
486: private static Class<?> getBoxingTypeIfPrimitive(Class<?> clazz) {
487: if (clazz.isPrimitive()) {
488: if (clazz == Boolean.TYPE) {
489: return Boolean.class;
490: }
491: if (clazz == Character.TYPE) {
492: return Character.class;
493: }
494: if (clazz == Byte.TYPE) {
495: return Byte.class;
496: }
497: if (clazz == Short.TYPE) {
498: return Short.class;
499: }
500: if (clazz == Integer.TYPE) {
501: return Integer.class;
502: }
503: if (clazz == Long.TYPE) {
504: return Long.class;
505: }
506: if (clazz == Float.TYPE) {
507: return Float.class;
508: }
509:
510: return Double.class;
511: } else {
512: return clazz;
513: }
514: }
515:
516: /*
517: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
518: */
519: private static Class<?>[] getComparingParamTypesForVarArgsMethod(Class<?>[] paramTypes, int length) {
520: Class<?>[] result = new Class<?>[length];
521: System.arraycopy(paramTypes, 0, result, 0, paramTypes.length - 1);
522: Class<?> type = paramTypes[paramTypes.length - 1].getComponentType();
523: for (int i = paramTypes.length - 1; i < length; i++) {
524: result[i] = type;
525: }
526:
527: return result;
528: }
529:
530: /*
531: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
532: */
533: private static final String paramString(Class<?>[] types) {
534: if (types != null) {
535: StringBuilder sb = new StringBuilder();
536: for (int i = 0; i < types.length; i++) {
537: if (types[i] == null) {
538: sb.append("null, ");
539: } else {
540: sb.append(types[i].getName()).append(", ");
541: }
542: }
543: if (sb.length() > 2) {
544: sb.setLength(sb.length() - 2);
545: }
546: return sb.toString();
547: }
548: return null;
549: }
550:
551: /*
552: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
553: */
554: static boolean isAssignableFrom(Class<?> src, Class<?> target) {
555: // src will always be an object
556: // Short-cut. null is always assignable to an object and in Jakarta Expression Language null
557: // can always be coerced to a valid value for a primitive
558: if (src == null) {
559: return true;
560: }
561:
562: target = getBoxingTypeIfPrimitive(target);
563:
564: return target.isAssignableFrom(src);
565: }
566:
567: /*
568: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
569: */
570: private static boolean isCoercibleFrom(Object src, Class<?> target) {
571: // TODO: This isn't pretty but it works. Significant refactoring would
572: // be required to avoid the exception.
573: try {
574: getExpressionFactory().coerceToType(src, target);
575: } catch (Exception e) {
576: return false;
577: }
578:
579: return true;
580: }
581:
582: /*
583: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
584: */
585: private static Class<?>[] getTypesFromValues(Object[] values) {
586: if (values == null) {
587: return null;
588: }
589:
590: Class<?> result[] = new Class<?>[values.length];
591: for (int i = 0; i < values.length; i++) {
592: if (values[i] == null) {
593: result[i] = null;
594: } else {
595: result[i] = values[i].getClass();
596: }
597: }
598:
599: return result;
600: }
601:
602: /*
603: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
604: *
605: * Get a public method form a public class or interface of a given method. Note that if a PropertyDescriptor is obtained
606: * for a non-public class that implements a public interface, the read/write methods will be for the class, and
607: * therefore inaccessible. To correct this, a version of the same method must be found in a superclass or interface.
608: *
609: */
610: static Method getMethod(Class<?> type, Method m) {
611: if (m == null || Modifier.isPublic(type.getModifiers())) {
612: return m;
613: }
614: Class<?>[] inf = type.getInterfaces();
615: Method mp = null;
616: for (int i = 0; i < inf.length; i++) {
617: try {
618: mp = inf[i].getMethod(m.getName(), m.getParameterTypes());
619: mp = getMethod(mp.getDeclaringClass(), mp);
620: if (mp != null) {
621: return mp;
622: }
623: } catch (NoSuchMethodException e) {
624: // Ignore
625: }
626: }
627: Class<?> sup = type.getSuperclass();
628: if (sup != null) {
629: try {
630: mp = sup.getMethod(m.getName(), m.getParameterTypes());
631: mp = getMethod(mp.getDeclaringClass(), mp);
632: if (mp != null) {
633: return mp;
634: }
635: } catch (NoSuchMethodException e) {
636: // Ignore
637: }
638: }
639: return null;
640: }
641:
642: /*
643: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
644: */
645: static Constructor<?> getConstructor(Class<?> type, Constructor<?> c) {
646: if (c == null || Modifier.isPublic(type.getModifiers())) {
647: return c;
648: }
649: Constructor<?> cp = null;
650: Class<?> sup = type.getSuperclass();
651: if (sup != null) {
652: try {
653: cp = sup.getConstructor(c.getParameterTypes());
654: cp = getConstructor(cp.getDeclaringClass(), cp);
655: if (cp != null) {
656: return cp;
657: }
658: } catch (NoSuchMethodException e) {
659: // Ignore
660: }
661: }
662: return null;
663: }
664:
665: /*
666: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
667: */
668: @SuppressWarnings("null")
669: static Object[] buildParameters(ELContext context, Class<?>[] parameterTypes, boolean isVarArgs, Object[] params) {
670: Object[] parameters = null;
671: if (parameterTypes.length > 0) {
672: parameters = new Object[parameterTypes.length];
673: int paramCount = params == null ? 0 : params.length;
674: if (isVarArgs) {
675: int varArgIndex = parameterTypes.length - 1;
676: // First argCount-1 parameters are standard
677: for (int i = 0; (i < varArgIndex && i < paramCount); i++) {
678: parameters[i] = context.convertToType(params[i], parameterTypes[i]);
679: }
680: // Last parameter is the varargs
681: if (parameterTypes.length == paramCount && parameterTypes[varArgIndex] == params[varArgIndex].getClass()) {
682: parameters[varArgIndex] = params[varArgIndex];
683: } else {
684: Class<?> varArgClass = parameterTypes[varArgIndex].getComponentType();
685: final Object varargs = Array.newInstance(varArgClass, (paramCount - varArgIndex));
686: for (int i = (varArgIndex); i < paramCount; i++) {
687: Array.set(varargs, i - varArgIndex, context.convertToType(params[i], varArgClass));
688: }
689: parameters[varArgIndex] = varargs;
690: }
691: } else {
692: for (int i = 0; i < parameterTypes.length && i < paramCount; i++) {
693: parameters[i] = context.convertToType(params[i], parameterTypes[i]);
694: }
695: }
696: }
697: return parameters;
698: }
699:
700: /*
701: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
702: */
703: private abstract static class Wrapper {
704:
705: public static List<Wrapper> wrap(Method[] methods, String name) {
706: List<Wrapper> result = new ArrayList<>();
707: for (Method method : methods) {
708: if (method.getName().equals(name)) {
709: result.add(new MethodWrapper(method));
710: }
711: }
712: return result;
713: }
714:
715: public static List<Wrapper> wrap(Constructor<?>[] constructors) {
716: List<Wrapper> result = new ArrayList<>();
717: for (Constructor<?> constructor : constructors) {
718: result.add(new ConstructorWrapper(constructor));
719: }
720: return result;
721: }
722:
723: public abstract Object unWrap();
724:
725: public abstract Class<?>[] getParameterTypes();
726:
727: public abstract boolean isVarArgs();
728:
729: public abstract boolean isBridge();
730: }
731:
732: /*
733: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
734: */
735: private static class MethodWrapper extends Wrapper {
736: private final Method m;
737:
738: public MethodWrapper(Method m) {
739: this.m = m;
740: }
741:
742: @Override
743: public Object unWrap() {
744: return m;
745: }
746:
747: @Override
748: public Class<?>[] getParameterTypes() {
749: return m.getParameterTypes();
750: }
751:
752: @Override
753: public boolean isVarArgs() {
754: return m.isVarArgs();
755: }
756:
757: @Override
758: public boolean isBridge() {
759: return m.isBridge();
760: }
761: }
762:
763: /*
764: * This method duplicates code in com.sun.el.util.ReflectionUtil. When making changes keep the code in sync.
765: */
766: private static class ConstructorWrapper extends Wrapper {
767: private final Constructor<?> c;
768:
769: public ConstructorWrapper(Constructor<?> c) {
770: this.c = c;
771: }
772:
773: @Override
774: public Object unWrap() {
775: return c;
776: }
777:
778: @Override
779: public Class<?>[] getParameterTypes() {
780: return c.getParameterTypes();
781: }
782:
783: @Override
784: public boolean isVarArgs() {
785: return c.isVarArgs();
786: }
787:
788: @Override
789: public boolean isBridge() {
790: return false;
791: }
792: }
793:
794: }